Skip to content

fix(skills): read skill markdown as UTF-8 - #4995

Open
JieZeng777 wants to merge 2 commits into
bytedance:mainfrom
JieZeng777:codex/fix-skill-validator-utf8
Open

fix(skills): read skill markdown as UTF-8#4995
JieZeng777 wants to merge 2 commits into
bytedance:mainfrom
JieZeng777:codex/fix-skill-validator-utf8

Conversation

@JieZeng777

Copy link
Copy Markdown

Why

On Windows systems whose default locale is not UTF-8, the skill creator validator reads SKILL.md with the platform default encoding. Localized UTF-8 skills can therefore fail validation with UnicodeDecodeError, even though the skill file itself is valid.

What changed

  • Read SKILL.md explicitly as UTF-8 in the skill creator validator.
  • Add a portable regression test that simulates a non-UTF-8 Windows default code page.
  • Document the UTF-8 contract for skill text resources and validation utilities.

Surface area

  • Frontend UI — page / component / setting / interaction under frontend/
  • Backend API — endpoint / SSE event / request-response shape under backend/app
  • Agents / LangGraph — agent node, graph wiring, langgraph.json, or prompt change
  • Sandboxdocker/ or sandboxed execution
  • Skills — change under skills/
  • Dependencies — new/upgraded entry in backend/pyproject.toml or frontend/package.json
  • Default behavior change — changes existing behavior without the user opting in
  • Docs / tests / CI only — no runtime behavior change

Screenshots / Recording

Not applicable; this change has no UI surface.

Bug fix verification

  • Test path that reproduces the bug: tests/skills/test_skill_creator_quick_validate.py
  • Did it go red on main and green on this branch? Yes. Before the fix, the regression test raised the simulated GBK UnicodeDecodeError; after the fix, it passes.

Validation

  • python -m pytest tests/skills -q — 52 passed
  • python -m ruff check --config backend/ruff.toml tests/skills/test_skill_creator_quick_validate.py — passed
  • python -m ruff format --check --config backend/ruff.toml tests/skills/test_skill_creator_quick_validate.py — passed
  • python skills/public/skill-creator/scripts/quick_validate.py skills/public/skill-creator — Skill is valid

AI assistance

Tool(s) used: Codex

How you used it: Codex helped inspect the Windows locale failure, write the regression test, implement the minimal encoding fix, update documentation, and run validation. I reviewed and understand the resulting change.

  • I've read and understand every line of this change and take responsibility for it — it's not unreviewed AI output.

@CLAassistant

CLAassistant commented Aug 24, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@github-actions github-actions Bot added area:docs Documentation and Markdown only area:skills Skills under skills/ or the skills harness risk:medium Medium risk: regular code changes size/S PR changes 20-100 lines labels Aug 24, 2026
@JieZeng777
JieZeng777 force-pushed the codex/fix-skill-validator-utf8 branch from 19c731d to 6e9e48f Compare August 24, 2026 07:04
@WillemJiang

Copy link
Copy Markdown
Collaborator

@JieZeng777 thanks for your contribution. Please click the CLA assitant button to sign the CLA first.

@JieZeng777

Copy link
Copy Markdown
Author

@WillemJiang Thanks! I’ve signed the CLA, and the license/cla check is now passing.

I also investigated the failing Skill Review CI. The four reported errors come from existing files in the skill-creator package and are unrelated to this PR’s UTF-8 change. This PR only changes quick_validate.py, but the CI reviews the entire package. Would you prefer that these pre-existing findings be handled separately, or should I include a narrowly scoped cleanup in this PR?

@willem-bd willem-bd left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solid, minimal fix and a well-targeted regression test. Three things worth addressing: the same locale-dependent read still exists in the sibling skill-creator scripts (notably utils.py: parse_skill_md, which is the SKILL.md reader for run_eval/run_loop/improve_description); the new hard UTF-8 decode turns a non-UTF-8 SKILL.md into an unhandled UnicodeDecodeError instead of the (False, message) contract that package_skill.py relies on; and the new regression test is not executed by any CI workflow, so it only protects local runs.


# Read and validate frontmatter
content = skill_md.read_text()
content = skill_md.read_text(encoding="utf-8")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix is correct but incomplete against the contract this PR adds to AGENTS.md. parse_skill_md() in skills/public/skill-creator/scripts/utils.py:9 still does (skill_path / "SKILL.md").read_text() with the platform codec, and it is the SKILL.md reader used by run_eval.py:279, run_loop.py:64 and run_loop.py:268, and improve_description.py:213 — so a localized UTF-8 skill still hits the exact UnicodeDecodeError this PR fixes, just through a different script.

Related, same root cause: init_skill.py:230 writes SKILL.md via write_text(skill_content) with no encoding, so on a non-UTF-8 Windows code page skill-creator emits a SKILL.md that already violates the UTF-8 rule. The JSON reads in run_eval.py:272, run_loop.py:261, improve_description.py:208/211 and generate_report.py:314 are locale-dependent too.


# Read and validate frontmatter
content = skill_md.read_text()
content = skill_md.read_text(encoding="utf-8")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With a strict UTF-8 decode, a SKILL.md that is not valid UTF-8 now raises UnicodeDecodeError out of validate_skill() instead of returning the (False, message) tuple that every other branch uses. skills/public/skill-creator/scripts/package_skill.py:72 imports and calls this directly (valid, message = validate_skill(skill_path)), so the caller gets a raw traceback instead of the friendly "Validation failed: ..." path.

Suggest wrapping the read in try/except UnicodeDecodeError and returning something like (False, "SKILL.md is not valid UTF-8") — that keeps the tuple contract and gives a diagnosable message (which also points at the encoding mismatch rather than looking like a validator crash).

return module


def test_validate_skill_reads_markdown_as_utf8(tmp_path: Path, monkeypatch) -> None:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This regression test is not wired into CI. No GitHub Actions workflow and no root Makefile target runs tests/skills/ — CI only executes backend/tests/ (backend-unit-tests.yml, backend-blocking-io-tests.yml, skill-review-ci.yml), and the root Makefile has no test target. So the guard only protects developers who run pytest tests/skills by hand at the repo root.

Worth adding this directory to a workflow (or a root make test) in the same PR, otherwise the encoding regression can quietly come back and the PR's "went red on main, green on branch" property is lost after merge.

@WillemJiang

Copy link
Copy Markdown
Collaborator

@JieZeng777, please take a look at the review comments. Now the CI should be fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:docs Documentation and Markdown only area:skills Skills under skills/ or the skills harness risk:medium Medium risk: regular code changes size/S PR changes 20-100 lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants